#include "main.hh"
#include "pliutil.hh"
#include <stdlib.h>
#include <assert.h>
//#include <iostream>
//using namespace std;

extern "C" {
  s_tfcell * core_bootstrap();

  //user's routine
  int hello_task();
  int hello_param_task();
  int show_net_name();
  int recv_eth_frame();
  int recv_eth_frame_finish();

  int trans_eth_frame();

  //for AHB/APB/DMA
  int apb_bridge_reset();
  int apb_bridge();

  int ahb_ram_write();
  int ahb_ram_read();
}

void init();

s_tfcell * core_bootstrap() 
{
  static s_tfcell my_tfs[] =
    {
    /*** Template for an entry:
    { usertask|userfunction, data,
      checktf(), sizetf(), calltf(), misctf(),
      "$tfname", forwref?, Vtool?, ErrMsg? },
    Example:
    { usertask, 0, my_check, 0, my_func, my_misctf, "$my_task" },
    ***/

    /*** add user entries here ***/
      {usertask, 0, 0, 0, hello_task, 0, "$hello", 1},
      {usertask, 0, 0, 0, hello_param_task, 0, "$hello_param", 1},

      {usertask, 0, 0, 0, show_net_name, 0, "$show_nets", 1},


      //tasks for leon2MAC
      {usertask, 0, 0, 0, recv_eth_frame, 0, "$recv_eth_frame", 1},
      {usertask, 0, 0, 0, recv_eth_frame_finish, 0, "$recv_eth_frame_finish", 1},

      {usertask, 0, 0, 0, trans_eth_frame, 0, "$trans_eth_frame", 1},

      //for AHB/APB/DMA
      {usertask, 0, 0, 0, apb_bridge_reset, 0, "$apb_bridge_reset", 1},
      {usertask, 0, 0, 0, apb_bridge, 0, "$apb_bridge", 1},

      {usertask, 0, 0, 0, ahb_ram_write, 0, "$ahb_ram_write", 1},
      {usertask, 0, 0, 0, ahb_ram_read, 0, "$ahb_ram_read", 1},

      
      {0} /*** final entry must be 0 ***/
    };
  io_printf("PLI tasks & functions register finished !\n");

  //some init
  init();
  
  return my_tfs;
}


////////////////////////////////////////////////////////////////////////////////////////////////////
// for ethernet MAC Layer CRC32, LSB first, shift left, print each step
unsigned int crc32_eth(unsigned char *buf, int len)
{
  int i, j;
  unsigned int CRC = 0xffffffff;
  for(i=0;i<len;i++)
    {
      unsigned char byte = buf[i];
      for(j=0;j<8;j++)
        {
          if((byte&0x1) ^ (CRC>>31))
            CRC = (CRC<<1) ^ 0x04c11db7;
          else
            CRC <<= 1;
          byte >>= 1;
        }
      // printf("Data : %02x, CRC : %08x\n", buf[i], CRC);
    }
  // return ~CRC;
  return CRC;
}
////////////////////////////////////////////////////////////////////////////////////////////////////

static unsigned char frame1[1024];
static unsigned char frame2[1024];
static unsigned char frame3[1024];
static unsigned char frame4[1024];
static unsigned char frame5[1024];

void gen_frame();


  
handle get_signal_hanle(char *netname)
{
  acc_initialize();
  acc_configure(accDisplayErrors, "false");
  //gate = acc_handle_tfarg(1);
  acc_configure(accEnableArgs, "acc_set_scope");
  //acc_set_scope(NULL, SIGNAL_SCOPE);
  acc_set_scope(NULL, "test");				//??
  //handle net = acc_handle_object("test.rst");
  handle net = acc_handle_object(netname);               //what's about this name ? test.rst or just rst ?
  if(!net) {
    acc_set_scope(NULL, NULL);
    net = acc_handle_object(netname);
    if(!net)
      {
        io_printf("not find signal : %s\n", netname);
        tf_dofinish();
      }
  }
  acc_close();
  return net;
}

unsigned int getBusNetValue(handle hd)
{
  s_acc_value v;
  v.format = accIntVal;
  acc_fetch_value(hd,"%%", &v);
  return v.value.integer;
}

unsigned int getSingleNetValue(handle hd)
{
  s_acc_value v;
  v.format = accScalarVal;
  acc_fetch_value(hd,"%%", &v);
  return v.value.scalar;
}

int get_signal_value(char *netname)
{
  // handle net = acc_handle_object("test.count");
  // s_acc_value v;
  // v.format = accScalarVal;
  // acc_fetch_value(net,"%%", &v);
  // io_printf("%x\n", v.value.scalar);

  //get_signal_hanle(const char *netname)

  // handle hd = get_signal_hanle(netname);
  // s_acc_value v;
  // v.format = accScalarVal;
  // acc_fetch_value(hd,"%%", &v);
  // return v.value.scalar;

  handle net = get_signal_hanle(netname);
  s_acc_value v;
  v.format = accIntVal;
  acc_fetch_value(net,"%%", &v);
  return v.value.integer;

}



int hello_task()
{
  // char *top_mod = get_top_module_name();
  // io_printf("top module is : %s\n", top_mod);

  
  handle net = acc_handle_object("test.count");
  s_acc_value v;
  v.format = accIntVal;
  acc_fetch_value(net,"%%", &v);
  //return v.value.integer;
  io_printf("get value from test.count : %x\n", v.value.integer);

  //io_printf("hello world\n");
  
  // int param = acc_fetch_tfarg_int(1);
  // io_printf("parameter is %d\n", param);
    
  // int val = get_signal_value("test.count");
  // io_printf("val is %x\n", val);
  // return 0;
}
int hello_param_task()
{
  int param = acc_fetch_tfarg_int(1);
  io_printf("get parameter from hello_param() : %d\n", param);
  
  // //int val = get_signal_value("test.count[0]");
  // //int val2 = get_signal_value("test.count[1]");
  // int val = get_signal_value("test.count");
  // io_printf("val is %x\n", val);
  return 0;
}

// int getSingleNetValue()
// {
//   if(!hd) return 0;
//   s_acc_value v;
//   v.format = accScalarVal;
//   acc_fetch_value(hd, "%%", &v);
//   return v.value.Scalar;
// }

int show_net_name()
{
  display_net_name();
}



static unsigned char recv_eth_frame_buf[1500+8];
static bool recv_valid_eth_frame = true;
static int recv_index = 0;

//received an eth frame
int recv_eth_frame_finish()
{
  if(recv_valid_eth_frame == false)
    {
      io_printf("receive Tx_er signal while in the ethernet frame ...\n");
      return 0;
    }
  io_printf("receive an ethernet frame with length %d :\n", recv_index-8);      //length strip the preamble
  //check the length ??
  
  //now process the received eth frame : recv_eth_frame
  for(int i=0;i<8;i++)
    io_printf("%02x,", recv_eth_frame_buf[i]);          //the preamble
  printf("\n");
  
  for(int i=8;i<recv_index;i++)
    {
      io_printf("%02x,", recv_eth_frame_buf[i]);        //the real frame 
    }
  io_printf("\n");

  //check the crc
  unsigned int crc = crc32_eth(&recv_eth_frame_buf[8], recv_index-8);
  io_printf("the crc is %08x", crc);
  if(crc == 0xc704dd7b)
    io_printf(" (check valid)\n");
  else
    io_printf(" (Error)\n");
  
     
  
  //then, clear the buffer for ready to receive the next frame
  recv_valid_eth_frame = true;
  recv_index = 0;
  
  // //int val = get_signal_value("test.count[0]");
  // //int val2 = get_signal_value("test.count[1]");
  // int val = get_signal_value("test.count");
  // io_printf("val is %x\n", val);
  return 0;
}

//tasks for leon2MAC
int recv_eth_frame()
{
  int tx_er = acc_fetch_tfarg_int(1);                                    //if the value contain 'x,z', then the result is not right
  int txd = acc_fetch_tfarg_int(2);
  // io_printf("Tx_er = %d, Txd = %x\n", tx_er, txd);
  if(tx_er)
    recv_valid_eth_frame = false;
  if(recv_valid_eth_frame == false)
    return 0;
  //tx_er is not asserted, receive the frame data
  recv_eth_frame_buf[recv_index++] = txd;

  return 0;
}




static unsigned char eth_frame_buf[1500+8];

struct eth_frame_header
{
  unsigned long long Preamble;
  unsigned char SFD;
  unsigned long long DA;
  unsigned long long SA;
  unsigned short LenType;               //2 octets
  // unsigned char *Data;                  //DATA/PAD/FCS
};

// unsigned char eth_frame_data_buf[1500+8];               //the legnth ??

static const int ETH_FRAME_MIN_LEN = 64;
static const int ETH_FRAME_MAX_LEN = 100;

// unsigned char * set_eth_header(const eth_frame_header &fh)
int set_eth_header(const eth_frame_header &fh)
{
  int index = 0;
  for(int i=0;i<7;i++)
    eth_frame_buf[index++] = (fh.Preamble >> ((6-i)*8)) & 0xff;
  eth_frame_buf[index++] = fh.SFD;
  for(int i=0;i<6;i++)
    eth_frame_buf[index++] = (fh.DA >> ((5-i)*8)) & 0xff;
  for(int i=0;i<6;i++)
    eth_frame_buf[index++] = (fh.SA >> ((5-i)*8)) & 0xff;
  eth_frame_buf[index++] = (fh.LenType>>8) & 0xff;
  eth_frame_buf[index++] = fh.LenType & 0xff;
  // return &eth_frame_buf[index];
  return index;
}

// append_crc(buf, index);
void append_crc(unsigned char *buf, int index)
{
  //gen the  CRC 
  unsigned int crc = crc32_eth(&buf[8], index-8);
  crc = ~crc;           //reverse
  // rolling the bits in each byte
  for(int j=24;j>=0;j-=8)       //24, 16, 8, 0
    {
      unsigned char byte = crc >> j;
      for(int i=0;i<4;i++)
        {
          if( ((byte >> i) ^ (byte >> (7-i))) & 1 )
            byte ^= (0x80>>i) | (1<<i);
        }
      buf[index++] = byte;
    }
}

int set_eth_header(unsigned char *buf, const eth_frame_header &fh)
{
  int index = 0;
  for(int i=0;i<7;i++)
    buf[index++] = (fh.Preamble >> ((6-i)*8)) & 0xff;
  buf[index++] = fh.SFD;
  for(int i=0;i<6;i++)
    buf[index++] = (fh.DA >> ((5-i)*8)) & 0xff;
  for(int i=0;i<6;i++)
    buf[index++] = (fh.SA >> ((5-i)*8)) & 0xff;
  buf[index++] = (fh.LenType>>8) & 0xff;
  buf[index++] = fh.LenType & 0xff;
  // return &buf[index];
  return index;
}

int eth_data_init()
{

  eth_frame_header fh = {     //  0x55555555555555,
    0x5555d555550003,
    
    // 0xab,       //error value
    0x75,       //right value
                                0x40123456789A,        //DA
                                0x40102030450,         //SA
                                0x8808                  //Length/Type
  };


  
  //used for bandwidth alloc (not for register)
  eth_frame_header gate_header = {
    0x5555d555550003,
    0x75,       //right value
    0x0180C2000001,     //multicast addr for GATE
    0x40102030450,         //SA
    0x8808                  //Length/Type
  };

  
  //   eth_frame_header fh = {       0x55555555555555,
  //                                 0xD5,
  //                                 0x140203040506,        //DA           //now eth_frame_buf[8]
  //                                 0x0708090A0B0C,         //SA
  //                                 0x0D0E                  //Length/Type
  // };

    //a frame
    // {0xd5,0x10,0x11,0x12,0x13,0x14,0x15,0x20,0x21,0x22,0x23,0x24,0x25,0x08,0x00,0x45,0x00,0x00,0x2e,0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x00,0x01,0x92,0xdb,0xe9,0xb7,0xd0,0x9d,0xf6,0x71};
      

    
  // unsigned char * buf = set_eth_header(fh);
  int index = set_eth_header(fh);
  // for(int i=0;i<46;i++)
  //   eth_frame_buf[index++] = rand()%256;
  unsigned char sd = 0x0f;
  for(int i=0;i<46;i++)
    eth_frame_buf[index++] = sd++;


  //for GATE (alloc)
  index = set_eth_header(gate_header);
  eth_frame_buf[index++] = 0x00;//opcode
  eth_frame_buf[index++] = 0x02;
  eth_frame_buf[index++] = 0x01;//timestamp
  eth_frame_buf[index++] = 0x02;
  eth_frame_buf[index++] = 0x03;
  eth_frame_buf[index++] = 0x04;
  eth_frame_buf[index++] = 0x11;//grant num
  eth_frame_buf[index++] = 0x01;//grant1 time
  eth_frame_buf[index++] = 0x02;
  eth_frame_buf[index++] = 0x03;
  eth_frame_buf[index++] = 0x31;        //start time
  eth_frame_buf[index++] = 0x00;//grant1 len
  eth_frame_buf[index++] = 0x7f;
  for(;index<60+8;)     //PAD
    eth_frame_buf[index++] = 0;
    
  //gen the  CRC 
  unsigned int crc = crc32_eth(&eth_frame_buf[8], index-8);
  crc = ~crc;           //reverse
  // rolling the bits in each byte
  for(int j=24;j>=0;j-=8)       //24, 16, 8, 0
    {
      unsigned char byte = crc >> j;
      for(int i=0;i<4;i++)
        {
          if( ((byte >> i) ^ (byte >> (7-i))) & 1 )
            byte ^= (0x80>>i) | (1<<i);
        }
      eth_frame_buf[index++] = byte;
    }
  // eth_frame_buf[index++] = 0x3e;
  // eth_frame_buf[index++] = 0x24;
  // eth_frame_buf[index++] = 0xfc;
  // eth_frame_buf[index++] = 0x2e;

  io_printf("the ethernet frame : \n");
  for(int i=8;i<64+8;i++)
    io_printf("0x%02x,", eth_frame_buf[i]);
  io_printf("\n");
  // exit(-1);
}



static bool trans_flag = false;
static int trans_clk_cnt = 0;

int trans_eth_frame()
{
  static unsigned char *trans_ptr = NULL;

  static unsigned char *trans_start_ptr = NULL;
  static unsigned char *trans_end_ptr;


    
  trans_clk_cnt++;
  if(trans_clk_cnt == 80)       //notice the IFG
    {
      trans_flag = true;
      // trans_ptr = NULL;
      io_printf("trans_clk_cnt == 200, now start sending ...\n");
      // eth_data_init();          //ready data
      trans_start_ptr = frame3; //discovery gate
      trans_end_ptr = trans_start_ptr + 64 + 8;   // 8 for Preamble/SFD   //point to the byte beyond the last valid one 
      //set the Rx_DV & Rx_er signal

      trans_ptr = NULL;
    }
  else if(trans_clk_cnt == 450)
    {
      trans_flag = true;
      // trans_ptr = NULL;
      trans_start_ptr = frame2;         //register
      trans_end_ptr = frame2 + 64 + 8;   // 8 for Preamble/SFD   //point to the byte beyond the last valid one

      trans_ptr = NULL;
    }
  else if(trans_clk_cnt == 650)
    {
      trans_flag = true;
      // trans_ptr = NULL;
      trans_start_ptr = frame1;         //normal gate
      trans_end_ptr = trans_start_ptr + 64 + 8;   // 8 for Preamble/SFD   //point to the byte beyond the last valid one

      trans_ptr = NULL;
    }
  else if(trans_clk_cnt == 1000)
    {
      trans_flag = true;
      // trans_ptr = NULL;
      trans_start_ptr = frame5;
      trans_end_ptr = trans_start_ptr + 64 + 8;   // 8 for Preamble/SFD   //point to the byte beyond the last valid one

      trans_ptr = NULL;
    }
  // else if(trans_clk_cnt == 1100)
  //   {
  //     trans_flag = true;
  //     trans_start_ptr = frame4;
  //     trans_end_ptr = trans_start_ptr + 64 + 8;   // 8 for Preamble/SFD   //point to the byte beyond the last valid one
  //     trans_ptr = NULL;
  //   }

    

  if(trans_flag == false)
  // if(trans_ptr == NULL)
    return 0;

  //start transmitting
  handle rx_dv = acc_handle_tfarg(1);
  handle rx_er = acc_handle_tfarg(2);
  handle rxd = acc_handle_tfarg(3);

  //for the first time, ready the frame data (only run for once for a ether frame)
  if(trans_ptr == NULL)
    {
      trans_ptr = trans_start_ptr;
      // eth_data_init();          //ready data
      // trans_ptr = eth_frame_buf;                //the transmit flag
      // trans_end_ptr = eth_frame_buf + 64 + 8;   // 8 for Preamble/SFD   //point to the byte beyond the last valid one 

      //set the Rx_DV & Rx_er signal
      s_acc_value v;
      v.format = accScalarVal;
      v.value.scalar = acc1;
      s_setval_delay delay = {{accSimTime}, accAssignFlag};        //the first param is ignored
      acc_set_value(rx_dv, &v, &delay);

      v.value.scalar = acc0;
      acc_set_value(rx_er, &v, &delay);
    }
  else if(trans_ptr == trans_end_ptr)       //the end signal
    {
      trans_flag = false;
      trans_ptr = NULL;

      //de-asserted the Rx_DV        //not here 
      s_acc_value v;
      v.format = accScalarVal;
      v.value.scalar = acc0;
      s_setval_delay delay = {{accSimTime}, accAssignFlag};
      acc_set_value(rx_dv, &v, &delay);
      v.value.scalar = acc0;
      acc_set_value(rx_er, &v, &delay);
      return 0;
    }

  //the transmit process
    {
      s_acc_value v;
      v.format = accIntVal;
      // v.value.integer = 0x34;
      v.value.integer = *trans_ptr;
      s_setval_delay delay = {{accSimTime}, accAssignFlag};        //the first param is ignored
      acc_set_value(rxd, &v, &delay);
      
      // io_printf("set value ...\n");
      
      if(trans_ptr < trans_end_ptr)
        trans_ptr++;
    }
  
  // else
  //   {
  //     //transmit finished
  //     trans_flag = false;
  //     trans_ptr = NULL;

  //     // //de-asserted the Rx_DV        //not here 
  //     // s_acc_value v;
  //     // v.format = accScalarVal;
  //     // v.value.scalar = acc0;
  //     // s_setval_delay delay = {{accSimTime}, accAssignFlag};
  //     // // s_setval_delay delay = {{accRealTime},accInertialDelay};
  //     // // delay.time.real= 0;
  //     // acc_set_value(rx_dv, &v, &delay);
  //     // v.value.scalar = acc0;
  //     // acc_set_value(rx_er, &v, &delay);
  //   }
}




int setSingleNetValue(handle hd, int val)
{
  if(!hd) return 0;
  s_acc_value v;
  v.format = accScalarVal;
  v.value.scalar = val ? acc1 : acc0;
  s_setval_delay delay = {{accSimTime}, accAssignFlag};
  acc_set_value(hd, &v, &delay);
  return 0;
}

int setBusNetValue(handle hd, int val)
{
  if(!hd) return 0;
  s_acc_value v;
  v.format = accIntVal;
  v.value.integer = val;
  s_setval_delay delay = {{accSimTime}, accAssignFlag};
  acc_set_value(hd, &v, &delay);
  return 0;
}



int apb_bridge_reset()
{
}

int apb_bridge()
{
  handle psel = acc_handle_tfarg(1);
  handle penable = acc_handle_tfarg(2);
  handle pwrite = acc_handle_tfarg(3);
  handle paddr = acc_handle_tfarg(4);
  handle pwdata = acc_handle_tfarg(5);

  // int prdata = acc_fetch_tfarg_int(6);
  handle prdata = acc_handle_tfarg(6);

  static int apb_cnt = 0;
  apb_cnt++;

  if(apb_cnt == 2)
    {
      //write DMA_CTRL regs
      setSingleNetValue(psel, 1);
      setSingleNetValue(penable, 0);
      setSingleNetValue(pwrite, 1);

      setBusNetValue(paddr, 0x80010002);        //for tx bd
      setBusNetValue(pwdata, 0x400);
    }
  else if(apb_cnt == 3)
    {
      setSingleNetValue(penable, 1);
    }
  else if(apb_cnt == 4)
    {
      setSingleNetValue(penable, 0);
      setBusNetValue(paddr, 0x80010003);        //for rx bd
      setBusNetValue(pwdata, 0x800);
    }
  else if(apb_cnt == 5)
    {
      setSingleNetValue(penable, 1);
    }
  else if(apb_cnt == 6)
    {
      setSingleNetValue(penable, 0);
      setBusNetValue(paddr, 0x80010000);        //start Tx
      setBusNetValue(pwdata, 1);
    }
  else if(apb_cnt == 7)
    {
      setSingleNetValue(penable, 1);
    }
  else if(apb_cnt == 8)
    {
      setSingleNetValue(psel, 0);
      setSingleNetValue(penable, 0);
    }
  
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
//ahb ram
static unsigned int ahb_ram[65536];

#define BIG_ENDIAN        //big endian or comment as little endian 


//read from ram, only for Big Endian
unsigned int read_ram(unsigned int addr, int size)
{
  io_printf("addr = %x\n", addr);
  unsigned int addr_index = addr>>2;
  unsigned int offset = addr&0x3;               //byte offset
  unsigned int data = ahb_ram[addr_index];

  if(size == 1)
    {
#ifdef BIG_ENDIAN
      return (data>>((3-offset)*8)) & 0xff;     //big endian
#else
      return (data>>(offset*8)) & 0xff;        //little endian
#endif
    }
  else if(size == 2)
    {
      assert(offset%2==0);      //halfword address alignment
#ifdef BIG_ENDIAN
      return (data>>((2-offset)*8)) & 0xffff;           //big endian
#else      
      return (data>>((offset)*8)) & 0xffff;          //little endian
#endif      
    }
  else if(size == 4)
    {
      assert(offset==0);
      return data;
    }
  else
    assert(false);              //not right size 
}

void write_ram(unsigned int addr, unsigned int data, int size)
{
  unsigned int addr_index = addr>>2;
  unsigned int offset = addr&0x3;
  unsigned int ori_data = ahb_ram[addr_index];
  
  if(size == 1)
    {
#ifdef BIG_ENDIAN
      int shift = (3-offset)*8;                 //big endian
#else      
      int shift = offset*8;                     //little endian
#endif      
      unsigned int umask = 0xff << shift;
      ahb_ram[addr_index] = (ori_data & ~umask) | (data << shift);
    }
  else if(size == 2)
    {
      assert(offset%2==0);      //halfword address alignment
#ifdef BIG_ENDIAN
      int shift = (2-offset)*8;         //big endian
#else      
      int shift = offset*8;
#endif      
      unsigned int umask = 0xffff << shift;
      ahb_ram[addr_index] = (ori_data & ~umask) | (data << shift);
    }
  else if(size == 4)
    {
      assert(offset==0);
      ahb_ram[addr_index] = data;
    }
  else
    assert(false);              //not right size 
}
////////////////////////////////////////////////////////////////////////////////////////////////////

int ahb_ram_write()
{
  handle ram_addr = acc_handle_tfarg(1);
  handle hwdata = acc_handle_tfarg(2);
  handle hsize = acc_handle_tfarg(3);
  
  unsigned int addr = getBusNetValue(ram_addr);
  unsigned int data = getBusNetValue(hwdata);
  unsigned int size = getBusNetValue(hsize);

  if(size==0)
    write_ram(addr, data, 1);
  else if(size==1)
    write_ram(addr, data, 2);
  else if(size==2)
    write_ram(addr, data, 4);
  else
    assert(false);
  
  io_printf("write data to %08x : %x\n", addr, data);
}

int ahb_ram_read()
{
  handle ram_addr = acc_handle_tfarg(1);
  handle hrdata = acc_handle_tfarg(2);
  handle hsize = acc_handle_tfarg(3);

  unsigned int addr = getBusNetValue(ram_addr);
  unsigned int size = getBusNetValue(hsize);
  unsigned int data;
  if(size==0)
    data = read_ram(addr, 1);
  else if(size==1)
    data = read_ram(addr, 2);
  else if(size==2)
    data = read_ram(addr, 4);
  else
    assert(false);

  setBusNetValue(hrdata, data);

  io_printf("read data from %08x : %x\n", addr, data);
}



//////////
void init()
{
  
  //for test
  for(int i=0;i<63356;i++)
    ahb_ram[i] = i+1;

  //a Tx BD
  // int length = 40;    //notice the ram is 32-bit wide, so the length in words is length/4
  int length = 100;    //notice the ram is 32-bit wide, so the length in words is length/4
  int EN = 1;
  int WR = 1;
  int IE =1;
  int UE = 0;
  unsigned int buf_addr = 0x8000;

  unsigned int data = (length&0x7ff) | ((EN&1)<<11) | ((WR&1)<<12) | ((IE&1)<<13) | ((UE&1)<<14);
  write_ram(0x400, data, 4);            //0x400 is the value which written to MAC's reg by APB Bridge
  write_ram(0x404, buf_addr, 4);        //the Tx Buffer 

  unsigned int data2 = ((length+40)&0x7ff) | ((EN&1)<<11) | ((WR&1)<<12) | ((IE&1)<<13) | ((UE&1)<<14);
  write_ram(0x408, data2, 4);            //0x408
  write_ram(0x40c, buf_addr+0x1000, 4);        //the Tx Buffer 
  //the Tx Buffer
  unsigned char ch = 12;
  for(int i=0;i<length;i++)
    write_ram(buf_addr+i, ch++, 1);

  // int eth_data_init()


  // write_ram(12,0x23,1); write_ram(13, 0x38,1); write_ram(14, 0x15,1); write_ram(15, 0x89,1);
  
  // unsigned int data;
  // printf("%x, %x, %x, %x \n", read_ram(12,1), read_ram(13,1), read_ram(14,1), read_ram(15,1));

  // printf("%x, %x \n", read_ram(12,2), read_ram(14, 2));

  // printf("%x \n", read_ram(12,4));
  


  gen_frame();

  
}



// static unsigned char frame1[1024];
// static unsigned char frame2[1024];
// static unsigned char frame3[1024];
// static unsigned char frame4[1024];

void gen_frame()
{

  eth_frame_header gate_normal_header = {
    0x5555d555550003,
    0x75,       //right value
    0x0180C2000001,     //multicast addr for GATE
    0x40102030450,         //SA
    0x8808                  //Length/Type
  };


  eth_frame_header register_header = {
    0x5555d55555ffff,                   //must be broadcast LLID 
    0x23,       //right value
    0x40123456789A,     //the ONU MAC addr      //08:00:27:48:a3:4f
    0x08002748a34f,         //SA
    0x8808                  //Length/Type
  };

  //gate for discovery !!
  eth_frame_header gate_discovery_header = {
    0x5555d55555ffff,
    0x23,       //right value
    0x0180C2000001,     //multicast addr for GATE
    0x40102030450,         //SA
    0x8808                  //Length/Type
  };

  eth_frame_header data_frame_header = {
    0x5555d555550003,
    0x75,       //right value
    0x40123456789A,     //the ONU MAC addr      //08:00:27:48:a3:4f
    0x08002748a34f,         //SA
    0x20                  //Length/Type
  };


  int index;


  index = set_eth_header(frame1, gate_normal_header);  //normal gate
  frame1[index++] = 0x00;//opcode
  frame1[index++] = 0x02;
  frame1[index++] = 0x12;//timestamp
  frame1[index++] = 0x13;
  frame1[index++] = 0x14;
  frame1[index++] = 0x15;
  frame1[index++] = 0x11;//grant num
  frame1[index++] = 0x12;//grant1 time
  frame1[index++] = 0x13;
  frame1[index++] = 0x14;
  frame1[index++] = 0x30;        //start time
  frame1[index++] = 0x00;//grant1 len
  frame1[index++] = 0x3f;
  for(;index<60+8;)     //PAD
    frame1[index++] = 0;
  append_crc(frame1, index);


  //register
  index = set_eth_header(frame2, register_header);
  frame2[index++] = 0x00;//opcode, register frame
  frame2[index++] = 0x05;
  frame2[index++] = 0x01;//timestamp
  frame2[index++] = 0x02;
  frame2[index++] = 0x03;
  frame2[index++] = 0x04;
  frame2[index++] = 0x00;//LLID
  frame2[index++] = 0x03;
  frame2[index++] = 0x03;//success or not
  frame2[index++] = 0xff;//sync time ??
  frame2[index++] = 0xff;
  frame2[index++] = 0x1f;//response for request 
  // frame2[index++] = 0x7f;
  for(;index<60+8;)     //PAD
    frame2[index++] = 0;
  append_crc(frame2, index);


  //GATE for discovery 
  index = set_eth_header(frame3, gate_discovery_header);
  frame3[index++] = 0x00;//opcode
  frame3[index++] = 0x02;
  frame3[index++] = 0x01;//timestamp
  frame3[index++] = 0x02;
  frame3[index++] = 0x03;
  frame3[index++] = 0x04;
  frame3[index++] = 0x19;//grant num //for discovery 
  frame3[index++] = 0x01;//grant1 time
  frame3[index++] = 0x02;
  frame3[index++] = 0x03;
  frame3[index++] = 0x50;        //start time
  frame3[index++] = 0x00;//grant1 len
  frame3[index++] = 0x2f;
  for(;index<60+8;)     //PAD
    frame3[index++] = 0;
  append_crc(frame3, index);



  //data frame
  index = set_eth_header(frame4, data_frame_header);
  for(;index<50+8;)
    frame4[index++] = rand();
  for(;index<60+8;)
    frame4[index++] = 0;
  append_crc(frame4, index);

  //normal gate
  index = set_eth_header(frame5, gate_normal_header);  //normal gate
  frame5[index++] = 0x00;//opcode
  frame5[index++] = 0x02;
  frame5[index++] = 0x22;//timestamp
  frame5[index++] = 0x23;
  frame5[index++] = 0x24;
  frame5[index++] = 0x25;
  frame5[index++] = 0x11;//grant num
  frame5[index++] = 0x22;//grant1 time
  frame5[index++] = 0x23;
  frame5[index++] = 0x24;
  frame5[index++] = 0x50;
  frame5[index++] = 0x00;//grant1 len
  frame5[index++] = 0xcf;
  for(;index<60+8;)     //PAD
    frame5[index++] = 0;
  append_crc(frame5, index);


}


  


